home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / Synthesizer Source / Synthesizer Folder / Level 0 Macintosh 20Jul94 / Screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  47.2 KB  |  1,560 lines  |  [TEXT/KAHL]

  1. /* Screen.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #pragma options(pack_enums)
  25. #include <Quickdraw.h>
  26. #include <Windows.h>
  27. #include <Menus.h>
  28. #include <Fonts.h>
  29. #include <TextEdit.h>
  30. #include <Dialogs.h>
  31. #include <Script.h>
  32. #pragma options(!pack_enums)
  33.  
  34. #include "Screen.h"
  35. #include "Menus.h"
  36. #include "Memory.h"
  37. #include "EventLoop.h"
  38. #include "Scrap.h"
  39. #include "Array.h"
  40. #include "Files.h"
  41.  
  42.  
  43. /* maximum string length that can be sized in a single call to TextWidth or DrawText */
  44. /* (such a big number doesn't actually make much sense since 65535 is the number of */
  45. /* pixels, so if there are 32767 chars, we are way over the QuickDraw limit.) */
  46. #define MAXTEXTSIZING (32767)
  47.  
  48.  
  49. /* this structure contains everything about a window */
  50. struct WinType
  51.     {
  52.         /* document window or dialog box */
  53.         WinForm                                WhatKindOfWindow;
  54.         /* callback routine for redrawing it */
  55.         void                                    (*UpdateRoutine)(void* Refcon);
  56.         /* reference value for callback */
  57.         void*                                    Refcon;
  58.         /* current clip rect (for AddClipRect) */
  59.         Rect                                    CurrentClipRect;
  60.         /* actual window record */
  61.         WindowRecord                    ActualWindow;
  62.     };
  63.  
  64.  
  65. /* structure for bitmap */
  66. struct Bitmap
  67.     {
  68.         /* bytes per row for larger than image or partial bitmaps */
  69.         short                                    BytesPerRow; /* 2 bytes */
  70.         /* dimensions of bitmap */
  71.         OrdType                                Width; /* 2 bytes */
  72.         OrdType                                Height; /* 2 bytes */
  73.         /* the bitmap that the system uses */
  74.         BitMap                                SystemBitmap; /* 14 bytes */
  75.         /* data array here (block will actually be as large as necessary) */
  76.         char                                    Data[1]; /* long word aligned (20th offset) */
  77.     };
  78.  
  79.  
  80. /* list of windows */
  81. static ArrayRec*                    OurWindowList;
  82.  
  83. /* list of windows that need to be updated */
  84. static ArrayRec*                    PendingDeferredUpdates;
  85.  
  86. /* debugging flag */
  87. EXECUTE(static MyBoolean    Initialized = False;)
  88.  
  89. /* pattern bitmap definitions.  patterns are 8x8 pixel blocks */
  90. static unsigned char            PatternMapping[5][8] =
  91.     {
  92.         {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* White */
  93.         {0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22}, /* Light Grey */
  94.         {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55}, /* Medium Grey */
  95.         {0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD}, /* Dark Grey */
  96.         {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} /* Black */
  97.     };
  98.  
  99. /* since I don't know how to get a list of fonts, I make this menu */
  100. /* which contains all of the fonts and then I extract the names from it */
  101. static MenuHandle                    FunnyFontMenu;
  102.  
  103. /* this array contains all of the modal dialog boxes.  the most recent one is */
  104. /* at the end of the array */
  105. static ArrayRec*                    DialogBoxList; /* of WinType's */
  106.  
  107.  
  108. /* Initialize the screen management subsystem.  This routine must be called before */
  109. /* any graphics routines are called.  this routine initializes the entire Level 0 */
  110. /* module set except for some optional modules (like Network).  if it returns  */
  111. /* False then initialization failed and the program must terminate immediately. */
  112. MyBoolean                        InitializeScreen(void)
  113.     {
  114.         ERROR(Initialized,PRERR(ForceAbort,"InitializeScreen called more than once"));
  115.         /* initialize operating system managers */
  116.         InitGraf(&qd.thePort);
  117.         InitFonts();
  118.         InitWindows();
  119.         TEInit();
  120.         InitDialogs(NIL);
  121.         InitCursor();
  122.         InitMenus();
  123. #ifdef THINK_C
  124.     #if __option(mc68020) || __option(mc68881)
  125.     #endif
  126.     #if __option(profile)
  127.         {
  128.             void                InitializeProfile(void);
  129.  
  130.             InitializeProfile();
  131.         }
  132.     #endif
  133. #endif
  134.         /* initialize our local memory manager */
  135.         if (!Eep_InitMemory())
  136.             {
  137.              FailurePoint1:
  138.                 return False;
  139.             }
  140.         /* initialize error handling.  no return code from this */
  141.         Eep_InitPRERR();
  142.         /* initialize our window array */
  143.         OurWindowList = NewArray();
  144.         if (OurWindowList == NIL)
  145.             {
  146.              FailurePoint2:
  147.                 Eep_FlushMemory();
  148.                 goto FailurePoint1;
  149.             }
  150.         /* initialize our deferred update list */
  151.         PendingDeferredUpdates = NewArray();
  152.         if (PendingDeferredUpdates == NIL)
  153.             {
  154.              FailurePoint3:
  155.                 DisposeArray(OurWindowList);
  156.                 goto FailurePoint2;
  157.             }
  158.         /* create dialog box array here */
  159.         DialogBoxList = NewArray();
  160.         if (DialogBoxList == NIL)
  161.             {
  162.              FailurePoint4:
  163.                 DisposeArray(PendingDeferredUpdates);
  164.                 goto FailurePoint3;
  165.             }
  166.         /* initialize cut and paste */
  167.         if (!Eep_InitializeScrapHandler())
  168.             {
  169.              FailurePoint5:
  170.                 DisposeArray(DialogBoxList);
  171.                 goto FailurePoint4;
  172.             }
  173.         /* initialize event loop */
  174.         if (!Eep_InitEventLoop())
  175.             {
  176.              FailurePoint6:
  177.                 Eep_ShutdownScrapHandler();
  178.                 goto FailurePoint5;
  179.             }
  180.         /* initialize menu subsystem */
  181.         if (!Eep_InitializeMenus())
  182.             {
  183.              FailurePoint7:
  184.                 Eep_ShutdownEventLoop();
  185.                 goto FailurePoint6;
  186.             }
  187.         /* initialize file system */
  188.         if (!Eep_InitializeFiles())
  189.             {
  190.              FailurePoint8:
  191.                 Eep_ShutdownMenus();
  192.                 goto FailurePoint7;
  193.             }
  194.         /* create the font menu for obtaining names of fonts */
  195.         /* menu manager uses menu IDs 256 and up, so we'll grab ID 1 */
  196.         FunnyFontMenu = NewMenu(1,"\pSilly Stupid Little Font Menu");
  197.         if (FunnyFontMenu == NIL)
  198.             {
  199.              FailurePoint9:
  200.                 Eep_ShutdownFiles();
  201.                 goto FailurePoint8;
  202.             }
  203.         AddResMenu(FunnyFontMenu,'FONT');
  204.         /* initialization done */
  205.         EXECUTE(Initialized = True;)
  206.         return True;
  207.     }
  208.  
  209.  
  210. /* close all open windows and perform any cleanup or server disconnection before */
  211. /* the program terminates */
  212. void                                ShutdownScreen(void)
  213.     {
  214.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  215.         /* shutdown subsystems in reverse order */
  216.         DisposeMenu(FunnyFontMenu); /* get rid of the funny font menu */
  217.         Eep_ShutdownFiles();
  218.         Eep_ShutdownMenus();
  219.         Eep_ShutdownEventLoop();
  220.         Eep_ShutdownScrapHandler();
  221.         /* clean up our own data structures */
  222.         ERROR(ArrayGetLength(OurWindowList) != 0,PRERR(AllowResume,
  223.             "ShutdownScreen:  there are still some windows open"));
  224.         DisposeArray(OurWindowList);
  225.         DisposeArray(PendingDeferredUpdates);
  226.         DisposeArray(DialogBoxList);
  227.         /* dump memory subsystem */
  228.         Eep_FlushMemory();
  229.         Eep_ShutdownPRERR();
  230.         EXECUTE(Initialized = False;)
  231. #ifdef THINK_C
  232.     #if __option(profile)
  233.         {
  234.             void                DumpProfile(void);
  235.             void                ProfileKillElement(unsigned char* FunctionName);
  236.  
  237.             ProfileKillElement("\pGetAnEvent");
  238.             ProfileKillElement("\pRelinquishCPUCheckCancel");
  239.             ProfileKillElement("\pPutFile");
  240.             ProfileKillElement("\pGetFileStandard");
  241.             ProfileKillElement("\pGetFileAny");
  242.             DumpProfile();
  243.         }
  244.     #endif
  245. #endif
  246.     }
  247.  
  248.  
  249. /* get size of screen.  If there are multiple screens, the result is implementation */
  250. /* defined, but should not be counted on.  On the Macintosh, this returns only the */
  251. /* size of the main screen.  Caveats aside, you are guarranteed that there is at */
  252. /* least this much screen space in the form of a complete rectangle. */
  253. OrdType                            GetScreenHeight(void)
  254.     {
  255.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  256.         return qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - GetMBarHeight();
  257.     }
  258.  
  259.  
  260. /* get size of screen.  If there are multiple screens, the result is implementation */
  261. /* defined, but should not be counted on.  On the Macintosh, this returns only the */
  262. /* size of the main screen.  Caveats aside, you are guarranteed that there is at */
  263. /* least this much screen space in the form of a complete rectangle. */
  264. OrdType                            GetScreenWidth(void)
  265.     {
  266.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  267.         return qd.screenBits.bounds.right - qd.screenBits.bounds.left;
  268.     }
  269.  
  270.  
  271. /* how big is a window's title bar */
  272. OrdType                            WindowTitleBarHeight(WinForm WindowKind)
  273.     {
  274.         switch (WindowKind)
  275.             {
  276.                 case eDocumentWindow:
  277.                     return 19;
  278.                 case eDialogWindow:
  279.                 case eModelessDialogWindow:
  280.                     return 6;
  281.                 default:
  282.                     EXECUTE(PRERR(AllowResume,"WindowTitleBarHeight:  Unknown window type"));
  283.             }
  284.     }
  285.  
  286.  
  287. /* how big are the other edges of a window */
  288. OrdType                            WindowOtherEdgeWidths(WinForm WindowKind)
  289.     {
  290.         switch (WindowKind)
  291.             {
  292.                 case eDocumentWindow:
  293.                     return 2;
  294.                 case eDialogWindow:
  295.                 case eModelessDialogWindow:
  296.                     return 6;
  297.                 default:
  298.                     EXECUTE(PRERR(AllowResume,"WindowTitleBarHeight:  Unknown window type"));
  299.             }
  300.     }
  301.  
  302.  
  303. /* create a new window.  if WindowKind = eDocumentWindow, then the window is a */
  304. /* standard window with a name (image is implementation defined).  In this case */
  305. /* Zoomable determines whether there will be a "Maximize" button, and Closable */
  306. /* determines whether there will be a "Close" button. */
  307. /* The window returned will be considered in the "disabled" state and any */
  308. /* objects installed in it should be disabled.  Eventually GetAnEvent will return */
  309. /* an active window change event disabling the window previously on top and */
  310. /* enabling this window.  if there are dialog boxes, then the window will be */
  311. /* created under the lowest dialog box */
  312. WinType*                        MakeNewWindow(WinForm WindowKind, WinCloseType Closable,
  313.                                             WinZoomType Zoomable, WinSizingType Resizing, OrdType Left,
  314.                                             OrdType Top, OrdType Width, OrdType Height,
  315.                                             void (*UpdateRoutine)(void* Refcon), void* Refcon)
  316.     {
  317.         WinType*                    Window;
  318.         Rect                            Where;
  319.         short                            WDef;
  320.  
  321.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  322.         ERROR(UpdateRoutine == NIL,PRERR(ForceAbort,
  323.             "MakeNewWindow:  can't have NIL update routine"));
  324.         /* allocate the window record */
  325.         Window = (WinType*)AllocPtrCanFail(sizeof(WinType),"WindowRecord");
  326.         if (Window == NIL)
  327.             {
  328.              FailurePoint1:
  329.                 return NIL;
  330.             }
  331.         /* add window to window list */
  332.         if (!ArrayAppendElement(OurWindowList,Window))
  333.             {
  334.              FailurePoint2:
  335.                 ReleasePtr((char*)Window);
  336.                 goto FailurePoint1;
  337.             }
  338.         /* create the actual window */
  339.         Where.left = Left;
  340.         Where.top = Top + GetMBarHeight();
  341.         Where.right = Left + Width;
  342.         Where.bottom = Top + Height + GetMBarHeight();
  343.         switch (WindowKind)
  344.             {
  345.                 case eDocumentWindow:
  346.                     if (Zoomable == eWindowZoomable)
  347.                         {
  348.                             WDef = zoomNoGrow;
  349.                         }
  350.                      else
  351.                         {
  352.                             WDef = noGrowDocProc;
  353.                         }
  354.                     break;
  355.                 case eDialogWindow:
  356.                     WDef = dBoxProc;
  357.                     break;
  358.                 case eModelessDialogWindow:
  359.                     WDef = movableDBoxProc;
  360.                     break;
  361.                 default:
  362.                     EXECUTE(PRERR(ForceAbort,"MakeNewWindow:  unknown WindowKind"));
  363.                     break;
  364.             }
  365.         if (NIL == NewWindow(&(Window->ActualWindow),&Where,"\p"/*notitle*/,
  366.             True/*visible*/,WDef,
  367.             (
  368.                 /* is the window a document window when there are dialog windows? */
  369.                 ((ArrayGetLength(DialogBoxList) != 0)
  370.                 && (WindowKind != eDialogWindow)
  371.                 && (WindowKind != eModelessDialogWindow))
  372.             ?
  373.                 /* yes -- create under lowest dialog */
  374.                 (GrafPort*)&(((WinType*)ArrayGetElement(DialogBoxList,0))->ActualWindow)
  375.             :
  376.                 /* no -- create on top */
  377.                 (GrafPort*)-1L/*windowinfront*/
  378.             ),(Closable == eWindowClosable),(long)Window/*refcon is window's base pointer*/))
  379.             {
  380.              FailurePoint3:
  381.                 ArrayDeleteElement(OurWindowList,ArrayFindElement(OurWindowList,Window));
  382.                 goto FailurePoint2;
  383.             }
  384.         /* initialize static fields */
  385.         Window->CurrentClipRect.left = 0;
  386.         Window->CurrentClipRect.top = 0;
  387.         Window->CurrentClipRect.right = Width;
  388.         Window->CurrentClipRect.bottom = Height;
  389.         Window->UpdateRoutine = UpdateRoutine;
  390.         Window->Refcon = Refcon;
  391.         Window->WhatKindOfWindow = WindowKind;
  392.         /* if it's a dialog box, then add it to the list */
  393.         if ((WindowKind == eDialogWindow) || (WindowKind == eModelessDialogWindow))
  394.             {
  395.                 if (!ArrayAppendElement(DialogBoxList,Window))
  396.                     {
  397.                         DisposeWindow((WindowPtr)&(Window->ActualWindow));
  398.                         goto FailurePoint3;
  399.                     }
  400.             }
  401.         return Window;
  402.     }
  403.  
  404.  
  405. /* change the size of the window.  The window will be guarranteed to be the specified */
  406. /* size, but significant portions may not be on screen, so be careful */
  407. void                                ResizeWindow(WinType* Window, OrdType Width, OrdType Height)
  408.     {
  409.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  410.         CheckPtrExistence(Window);
  411.         /* change window size */
  412.         SizeWindow((WindowPtr)&(Window->ActualWindow),Width,Height,False);
  413.         /* invalidate the window so it gets updated */
  414.         SetPort((WindowPtr)&(Window->ActualWindow));
  415.         InvalRect(&(Window->ActualWindow.port.portRect));
  416.     }
  417.  
  418.  
  419. /* close a window and release all associated space.  The window refnum may be reused */
  420. /* An active window change event will be issued activating the window that is */
  421. /* next in the stack.  If there are dialog boxes open, then the most recently */
  422. /* created one must be disposed or it is an error. */
  423. void                                KillWindow(WinType* Window)
  424.     {
  425.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  426.         CheckPtrExistence(Window);
  427.         ERROR((ArrayGetLength(DialogBoxList) != 0) && (ArrayFindElement(DialogBoxList,
  428.             Window) != ArrayGetLength(DialogBoxList) - 1),PRERR(ForceAbort,
  429.             "KillWindow:  dialog boxes exist and window isn't the topmost dialog box."));
  430.         Eep_WindowDying(Window);
  431.         ArrayDeleteElement(OurWindowList,ArrayFindElement(OurWindowList,Window));
  432.         if (ArrayGetLength(DialogBoxList) != 0)
  433.             {
  434.                 ERROR(ArrayFindElement(DialogBoxList,Window) == -1,PRERR(ForceAbort,
  435.                     "KillWindow:  couldn't find dialog box in the list"));
  436.                 ArrayDeleteElement(DialogBoxList,ArrayFindElement(DialogBoxList,Window));
  437.             }
  438.         /* remove it from the pending updates list if it's still there */
  439.         if (ArrayFindElement(PendingDeferredUpdates,Window) >= 0)
  440.             {
  441.                 ArrayDeleteElement(PendingDeferredUpdates,
  442.                     ArrayFindElement(PendingDeferredUpdates,Window));
  443.             }
  444.         /* dispose the OS window */
  445.         DisposeWindow((WindowPtr)&(Window->ActualWindow));
  446.         /* dispose the window object */
  447.         ReleasePtr((char*)Window);
  448.     }
  449.  
  450.  
  451. /* get the size of the usable portion of the window */
  452. OrdType                            GetWindowHeight(WinType* Window)
  453.     {
  454.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  455.         CheckPtrExistence(Window);
  456.         return Window->ActualWindow.port.portRect.bottom
  457.             - Window->ActualWindow.port.portRect.top;
  458.     }
  459.  
  460.  
  461. /* get the size of the usable portion of the window */
  462. OrdType                            GetWindowWidth(WinType* Window)
  463.     {
  464.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  465.         CheckPtrExistence(Window);
  466.         return Window->ActualWindow.port.portRect.right
  467.             - Window->ActualWindow.port.portRect.left;
  468.     }
  469.  
  470.  
  471. /* Get the global coordinate location of the window */
  472. OrdType                            GetWindowXStart(WinType* Window)
  473.     {
  474.         Point                            Delta = {0,0};
  475.  
  476.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  477.         CheckPtrExistence(Window);
  478.         /* this is really goofy, but I can't think of any other way of doing it. */
  479.         SetPort((WindowPtr)&(Window->ActualWindow));
  480.         LocalToGlobal(&Delta); /* find top-left with respect to screen */
  481.         return Delta.h;
  482.     }
  483.  
  484.  
  485. /* Get the global coordinate location of the window */
  486. OrdType                            GetWindowYStart(WinType* Window)
  487.     {
  488.         Point            Delta = {0,0};
  489.  
  490.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  491.         CheckPtrExistence(Window);
  492.         SetPort((WindowPtr)&(Window->ActualWindow));
  493.         LocalToGlobal(&Delta); /* find top-left with respect to screen */
  494.         return Delta.v - GetMBarHeight();
  495.     }
  496.  
  497.  
  498. /* Adjust the global position of the window. */
  499. void                                SetWindowPosition(WinType* Window, OrdType NewXLocation,
  500.                                             OrdType NewYLocation)
  501.     {
  502.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  503.         CheckPtrExistence(Window);
  504.         MoveWindow((WindowPtr)&(Window->ActualWindow),NewXLocation,
  505.             NewYLocation + GetMBarHeight(),False);
  506.     }
  507.  
  508.  
  509. /* Get what type of window it is */
  510. WinForm                            GetWindowKind(WinType* Window)
  511.     {
  512.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  513.         CheckPtrExistence(Window);
  514.         return Window->WhatKindOfWindow;
  515.     }
  516.  
  517.  
  518. /* allow system to resize window after user clicked in some area */
  519. void                                UserGrowWindow(WinType* Window, OrdType X, OrdType Y)
  520.     {
  521.         Rect                            Limits = {64,64,32767,32767};
  522.         Point                            Where;
  523.         unsigned long            NewSize;
  524.  
  525.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  526.         CheckPtrExistence(Window);
  527.         SetPort((WindowPtr)&(Window->ActualWindow));
  528.         Where.h = X;
  529.         Where.v = Y;
  530.         LocalToGlobal(&Where);
  531.         NewSize = GrowWindow((WindowPtr)&(Window->ActualWindow),Where,&Limits);
  532.         SizeWindow((WindowPtr)&(Window->ActualWindow),
  533.             NewSize & 0xffff,(NewSize >> 16) & 0xffff,False);
  534.         Limits.left = 0;
  535.         Limits.top = 0;
  536.         Limits.right = GetWindowWidth(Window);
  537.         Limits.bottom = GetWindowHeight(Window);
  538.         /* invalidate window so it gets redrawn */
  539.         EraseRect(&Limits);
  540.         InvalRect(&Limits);
  541.     }
  542.  
  543.  
  544. /* bring window to the top of the window stack.  this will be silently ignored */
  545. /* if there are dialog boxes open. */
  546. void                                ActivateThisWindow(WinType* Window)
  547.     {
  548.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  549.         CheckPtrExistence(Window);
  550.         if (ArrayGetLength(DialogBoxList) == 0)
  551.             {
  552.                 /* only do it if there aren't any dialog boxes */
  553.                 SelectWindow((WindowPtr)&(Window->ActualWindow));
  554.             }
  555.     }
  556.  
  557.  
  558. /* this function is used by MakeWindowFitOnScreen */
  559. static MyBoolean        SeeIfWindowFitsOnScreen(OrdType X, OrdType Y,
  560.                                             OrdType Width, OrdType Height)
  561.     {
  562.         RgnHandle                    OurRegion;
  563.         RgnHandle                    Intersection;
  564.         MyBoolean                    Result;
  565.  
  566.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  567.  
  568.         /* default value:  in case we run out of memory, don't do anything */
  569.         Result = True;
  570.         /* we add some constants in here to account for window title bar */
  571.         Y = Y + GetMBarHeight() - 19;
  572.         Height = Height + 19;
  573.  
  574.         /* create a region for the window the user wants to create */
  575.         OurRegion = NewRgn();
  576.         if (OurRegion != NIL)
  577.             {
  578.                 SetRectRgn(OurRegion,X,Y,X + Width,Y + Height);
  579.  
  580.                 /* create a region to get the intersection of the window & the screen */
  581.                 Intersection = NewRgn();
  582.                 if (Intersection != NIL)
  583.                     {
  584.                         /* find the intersection of the regions */
  585.                         SectRgn(GetGrayRgn(),OurRegion,Intersection);
  586.  
  587.                         /* if the window region and the intersection are equal, then the window */
  588.                         /* fits on the screen */
  589.                         Result = EqualRgn(Intersection,OurRegion);
  590.  
  591.                         DisposeRgn(Intersection);
  592.                     }
  593.  
  594.                 DisposeRgn(OurRegion);
  595.             }
  596.  
  597.         return Result;
  598.     }
  599.  
  600.  
  601. /* this routine helps make sure the rectangle fits on the screen.  If the rectangle */
  602. /* already fits on the screen, X and Y will not be adjusted, but if it doesn't, some */
  603. /* undefined adjustment will be made to ensure that the rectangle fits on the screen. */
  604. /* If the rectangle is so large that it can't be made to fit on the screen, then */
  605. /* the size of the window is reduced so that the window will fit on screen. */
  606. void                                MakeWindowFitOnScreen(OrdType* X, OrdType* Y,
  607.                                             OrdType* Width, OrdType* Height)
  608.     {
  609.         RgnHandle                    OurRegion;
  610.         RgnHandle                    Intersection;
  611.  
  612.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  613.         ERROR((X == NIL) || (Y == NIL) || (Width == NIL) || (Height == NIL),PRERR(ForceAbort,
  614.             "MakeWindowFitOnScreen:  an output parameter is NIL"));
  615.         if (!SeeIfWindowFitsOnScreen(*X,*Y,*Width,*Height))
  616.             {
  617.                 *X = 3;
  618.                 *Y = 23;
  619.                 if (!SeeIfWindowFitsOnScreen(*X,*Y,*Width,*Height))
  620.                     {
  621.                         if (*Width > GetScreenWidth() - *X - 2 - 1)
  622.                             {
  623.                                 *Width = GetScreenWidth() - *X - 2 - 1;
  624.                             }
  625.                         if (*Height > GetScreenHeight() - *Y - 2 - 1)
  626.                             {
  627.                                 *Height = GetScreenHeight() - *Y - 2 - 1;
  628.                             }
  629.                     }
  630.             }
  631.     }
  632.  
  633.  
  634. /* obtain the edge of a window, conforming to the user interface */
  635. /* guidelines of the implementation's platform */
  636. OrdType                            AlertLeftEdge(OrdType AlertWidth)
  637.     {
  638.         short                            Temp;
  639.  
  640.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  641.         Temp = (GetScreenWidth() - AlertWidth) / 2;
  642.         if (Temp < 4)
  643.             {
  644.                 Temp = 4;
  645.             }
  646.         return Temp;
  647.     }
  648.  
  649.  
  650. /* obtain the edge of a window, conforming to the user interface */
  651. /* guidelines of the implementation's platform */
  652. OrdType                            AlertTopEdge(OrdType AlertHeight)
  653.     {
  654.         short                            Temp;
  655.  
  656.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  657.         Temp = (GetScreenHeight() / 3) - AlertHeight;
  658.         if (Temp < 4 + 20 + GetMBarHeight())
  659.             {
  660.                 Temp = 4 + 20 + GetMBarHeight();
  661.             }
  662.         return Temp;
  663.     }
  664.  
  665.  
  666. /* obtain the edge of a window, conforming to the user interface */
  667. /* guidelines of the implementation's platform */
  668. OrdType                            DialogLeftEdge(OrdType DialogWidth)
  669.     {
  670.         short                            Temp;
  671.  
  672.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  673.         Temp = (GetScreenWidth() - DialogWidth) / 2;
  674.         if (Temp < 4)
  675.             {
  676.                 Temp = 4;
  677.             }
  678.         return Temp;
  679.     }
  680.  
  681.  
  682. /* obtain the edge of a window, conforming to the user interface */
  683. /* guidelines of the implementation's platform */
  684. OrdType                            DialogTopEdge(OrdType DialogHeight)
  685.     {
  686.         short                Temp;
  687.  
  688.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  689.         Temp = (GetScreenHeight() - DialogHeight) / 3;
  690.         if (Temp < 4 + 20 + GetMBarHeight())
  691.             {
  692.                 Temp = 4 + 20 + GetMBarHeight();
  693.             }
  694.         return Temp;
  695.     }
  696.  
  697.  
  698. /* change window's name.  name should be a null-terminated string.  the only windows */
  699. /* guarranteed to have a title bar are eDocumentWindow's. */
  700. void                                SetWindowName(WinType* Window, char* Name)
  701.     {
  702.         unsigned char            NameTemp[256];
  703.         long                            Scan;
  704.  
  705.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  706.         CheckPtrExistence(Window);
  707.         ERROR(Name == NIL,PRERR(ForceAbort,"SetWindowName:  name is NIL"));
  708.         Scan = 0;
  709.         while ((Scan < 255) && (Name[Scan] != 0))
  710.             {
  711.                 NameTemp[Scan + 1] = Name[Scan];
  712.                 Scan += 1;
  713.             }
  714.         NameTemp[0] = Scan;
  715.         SetWTitle((WindowPtr)&(Window->ActualWindow),NameTemp);
  716.     }
  717.  
  718.  
  719. /* invoke a window's update routine */
  720. void                                CallWindowUpdate(WinType* Window)
  721.     {
  722.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  723.         CheckPtrExistence(Window);
  724.         (*Window->UpdateRoutine)(Window->Refcon);
  725.     }
  726.  
  727.  
  728. /* if the program is doing something so that processing an update event would */
  729. /* cause it to crash, then the window is marked and will be redrawn as soon as */
  730. /* possible.   This is used during RelinquishCPU in the EventLoop module since */
  731. /* the windowing system might be in an inconsistent state when that routine is */
  732. /* called.  (If we ignored the event, then the window would not be redrawn at all) */
  733. void                                MarkForDeferredUpdate(WinType* Window)
  734.     {
  735.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  736.         CheckPtrExistence(Window);
  737.         if (ArrayFindElement(PendingDeferredUpdates,Window) < 0)
  738.             {
  739.                 /* don't add it to list unless it isn't there */
  740.                 /* if this fails, then it'll just not redraw the window. */
  741.                 ArrayAppendElement(PendingDeferredUpdates,Window);
  742.             }
  743.     }
  744.  
  745.  
  746. /* redraw all windows whose updates have been deferred */
  747. void                                PerformDeferredUpdates(void)
  748.     {
  749.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  750.         while (ArrayGetLength(PendingDeferredUpdates) != 0)
  751.             {
  752.                 WinType*                    Window;
  753.  
  754.                 /* get the window */
  755.                 Window = (WinType*)ArrayGetElement(PendingDeferredUpdates,0);
  756.                 CheckPtrExistence(Window);
  757.                 /* remove the window from the deferred update list */
  758.                 ArrayDeleteElement(PendingDeferredUpdates,0);
  759.                 /* erase window */
  760.                 SetClipRect(Window,0,0,GetWindowWidth(Window),GetWindowHeight(Window));
  761.                 DrawBoxErase(Window,0,0,GetWindowWidth(Window),GetWindowHeight(Window));
  762.                 /* call the redraw callback */
  763.                 CallWindowUpdate(Window);
  764.             }
  765.     }
  766.  
  767.  
  768. /* get the refcon from the window */
  769. void*                                GetWindowRefcon(WinType* Window)
  770.     {
  771.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  772.         CheckPtrExistence(Window);
  773.         return Window->Refcon;
  774.     }
  775.  
  776.  
  777. /* set the clipping rectangle for the window.  Drawing outside of this rectangle */
  778. /* will not be change any of the window */
  779. void                                SetClipRect(WinType* Window, OrdType Left, OrdType Top,
  780.                                             OrdType Width, OrdType Height)
  781.     {
  782.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  783.         CheckPtrExistence(Window);
  784.         SetPort((WindowPtr)&(Window->ActualWindow));
  785.         Window->CurrentClipRect.left = Left;
  786.         Window->CurrentClipRect.top = Top;
  787.         Window->CurrentClipRect.right = Left + Width;
  788.         Window->CurrentClipRect.bottom = Top + Height;
  789.         ClipRect(&(Window->CurrentClipRect));
  790.     }
  791.  
  792.  
  793. /* constrain the clipping rectangle for the window.  The new clipping rectangle is */
  794. /* the intersection of the specified one and the previous one. */
  795. void                                AddClipRect(WinType* Window, OrdType Left, OrdType Top,
  796.                                             OrdType Width, OrdType Height)
  797.     {
  798.         Rect                            Old;
  799.  
  800.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  801.         CheckPtrExistence(Window);
  802.         SetPort((WindowPtr)&(Window->ActualWindow));
  803.         Old = Window->CurrentClipRect;
  804.         Window->CurrentClipRect.left = Left;
  805.         Window->CurrentClipRect.top = Top;
  806.         Window->CurrentClipRect.right = Left + Width;
  807.         Window->CurrentClipRect.bottom = Top + Height;
  808.         SectRect(&(Window->CurrentClipRect),&Old,&(Window->CurrentClipRect));
  809.         ClipRect(&(Window->CurrentClipRect));
  810.     }
  811.  
  812.  
  813. /* returns True if any part of the specified rectangle in the window is visible. */
  814. /* this is used for making redrawing more efficient. */
  815. MyBoolean                        IsRectVisible(WinType* Window, OrdType Left, OrdType Top,
  816.                                             OrdType Width, OrdType Height)
  817.     {
  818.         Rect                            Location;
  819.  
  820.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  821.         CheckPtrExistence(Window);
  822.         Location.left = Left;
  823.         Location.top = Top;
  824.         Location.right = Left + Width;
  825.         Location.bottom = Top + Height;
  826.         return (MyBoolean)RectInRgn(&Location,Window->ActualWindow.port.visRgn);
  827.     }
  828.  
  829.  
  830. /* Draw a line one pixel thick.  XDisp and YDisp may be negative. */
  831. void                                DrawLine(WinType* Window, Patterns Pattern,
  832.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  833.     {
  834.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  835.         CheckPtrExistence(Window);
  836.         SetPort((WindowPtr)&(Window->ActualWindow));
  837.         PenPat(PatternMapping[Pattern - eWhite]);
  838.         PenMode(srcCopy);
  839.         MoveTo(X,Y);
  840.         LineTo(X + XDisp,Y + YDisp);
  841.     }
  842.  
  843.  
  844. /* Draw a box with a 1 pixel thick frame.  Note that the last pixel touched */
  845. /* is X + XDisp - 1 and Y + YDisp - 1. */
  846. void                                DrawBoxFrame(WinType* Window, Patterns Pattern,
  847.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  848.     {
  849.         Rect                            Temp;
  850.  
  851.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  852.         CheckPtrExistence(Window);
  853.         SetPort((WindowPtr)&(Window->ActualWindow));
  854.         PenPat(PatternMapping[Pattern - eWhite]);
  855.         PenMode(srcCopy);
  856.         Temp.left = X;
  857.         Temp.top = Y;
  858.         Temp.right = X + XDisp;
  859.         Temp.bottom = Y + YDisp;
  860.         FrameRect(&Temp);
  861.     }
  862.  
  863.  
  864. /* paint the box with the specified pattern */
  865. void                                DrawBoxPaint(WinType* Window, Patterns Pattern,
  866.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  867.     {
  868.         Rect                            Temp;
  869.  
  870.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  871.         CheckPtrExistence(Window);
  872.         SetPort((WindowPtr)&(Window->ActualWindow));
  873.         PenPat(PatternMapping[Pattern - eWhite]);
  874.         PenMode(srcCopy);
  875.         Temp.left = X;
  876.         Temp.top = Y;
  877.         Temp.right = X + XDisp;
  878.         Temp.bottom = Y + YDisp;
  879.         PaintRect(&Temp);
  880.     }
  881.  
  882.  
  883. /* paint the box with white */
  884. void                                DrawBoxErase(WinType* Window, OrdType X, OrdType Y,
  885.                                             OrdType XDisp, OrdType YDisp)
  886.     {
  887.         Rect                            Temp;
  888.  
  889.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  890.         CheckPtrExistence(Window);
  891.         SetPort((WindowPtr)&(Window->ActualWindow));
  892.         Temp.left = X;
  893.         Temp.top = Y;
  894.         Temp.right = X + XDisp;
  895.         Temp.bottom = Y + YDisp;
  896.         EraseRect(&Temp);
  897.     }
  898.  
  899.  
  900. #if 0
  901. /* And-mask the contents of the box with the pattern */
  902. void                                DrawBoxScreen(WinType* Window, Patterns Pattern,
  903.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp);
  904.     {
  905.         Rect                            Temp;
  906.  
  907.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  908.         CheckPtrExistence(Window);
  909.         SetPort((WindowPtr)&(Window->ActualWindow));
  910.         PenPat(PatternMapping[Pattern - eWhite]);
  911.         PenMode(srcBic);
  912.         Temp.left = X;
  913.         Temp.top = Y;
  914.         Temp.right = X + XDisp;
  915.         Temp.bottom = Y + YDisp;
  916.         PaintRect(&Temp);
  917.     }
  918. #endif
  919.  
  920.  
  921. /* Draw a box, but round off the corners with circles. */
  922. void                                DrawRoundBoxFrame(WinType* Window, Patterns Pattern,
  923.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp,
  924.                                             OrdType DiameterX, OrdType DiameterY)
  925.     {
  926.         Rect                            Temp;
  927.  
  928.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  929.         CheckPtrExistence(Window);
  930.         SetPort((WindowPtr)&(Window->ActualWindow));
  931.         PenPat(PatternMapping[Pattern - eWhite]);
  932.         PenMode(srcCopy);
  933.         Temp.left = X;
  934.         Temp.top = Y;
  935.         Temp.right = X + XDisp;
  936.         Temp.bottom = Y + YDisp;
  937.         FrameRoundRect(&Temp,DiameterX,DiameterY);
  938.     }
  939.  
  940.  
  941. /* Draw a box, but round off the corners with circles. */
  942. void                                DrawRoundBoxPaint(WinType* Window, Patterns Pattern,
  943.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp,
  944.                                             OrdType DiameterX, OrdType DiameterY)
  945.     {
  946.         Rect                            Temp;
  947.  
  948.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  949.         CheckPtrExistence(Window);
  950.         SetPort((WindowPtr)&(Window->ActualWindow));
  951.         PenPat(PatternMapping[Pattern - eWhite]);
  952.         PenMode(srcCopy);
  953.         Temp.left = X;
  954.         Temp.top = Y;
  955.         Temp.right = X + XDisp;
  956.         Temp.bottom = Y + YDisp;
  957.         PaintRoundRect(&Temp,DiameterX,DiameterY);
  958.     }
  959.  
  960.  
  961. /* Draw a box, but round off the corners with circles. */
  962. void                                DrawRoundBoxErase(WinType* Window, OrdType X, OrdType Y,
  963.                                             OrdType XDisp, OrdType YDisp, OrdType DiameterX, OrdType DiameterY)
  964.     {
  965.         Rect                            Temp;
  966.  
  967.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  968.         CheckPtrExistence(Window);
  969.         SetPort((WindowPtr)&(Window->ActualWindow));
  970.         Temp.left = X;
  971.         Temp.top = Y;
  972.         Temp.right = X + XDisp;
  973.         Temp.bottom = Y + YDisp;
  974.         EraseRoundRect(&Temp,DiameterX,DiameterY);
  975.     }
  976.  
  977.  
  978. void                                DrawCircleFrame(WinType* Window, Patterns Pattern,
  979.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  980.     {
  981.         Rect                            Temp;
  982.  
  983.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  984.         CheckPtrExistence(Window);
  985.         SetPort((WindowPtr)&(Window->ActualWindow));
  986.         PenPat(PatternMapping[Pattern - eWhite]);
  987.         PenMode(srcCopy);
  988.         Temp.left = X;
  989.         Temp.top = Y;
  990.         Temp.right = X + XDisp;
  991.         Temp.bottom = Y + YDisp;
  992.         FrameOval(&Temp);
  993.     }
  994.  
  995.  
  996. void                                DrawCirclePaint(WinType* Window, Patterns Pattern,
  997.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  998.     {
  999.         Rect                            Temp;
  1000.  
  1001.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1002.         CheckPtrExistence(Window);
  1003.         SetPort((WindowPtr)&(Window->ActualWindow));
  1004.         PenPat(PatternMapping[Pattern - eWhite]);
  1005.         PenMode(srcCopy);
  1006.         Temp.left = X;
  1007.         Temp.top = Y;
  1008.         Temp.right = X + XDisp;
  1009.         Temp.bottom = Y + YDisp;
  1010.         PaintOval(&Temp);
  1011.     }
  1012.  
  1013.  
  1014. void                                DrawCircleErase(WinType* Window, OrdType X, OrdType Y,
  1015.                                             OrdType XDisp, OrdType YDisp)
  1016.     {
  1017.         Rect            Temp;
  1018.  
  1019.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1020.         CheckPtrExistence(Window);
  1021.         SetPort((WindowPtr)&(Window->ActualWindow));
  1022.         Temp.left = X;
  1023.         Temp.top = Y;
  1024.         Temp.right = X + XDisp;
  1025.         Temp.bottom = Y + YDisp;
  1026.         EraseOval(&Temp);
  1027.     }
  1028.  
  1029.  
  1030. /* fill a triangle */
  1031. void                                DrawTrianglePaint(WinType* Window, Patterns Pattern, OrdType X1,
  1032.                                             OrdType Y1, OrdType X2, OrdType Y2, OrdType X3, OrdType Y3)
  1033.     {
  1034.         PolyHandle                Poly;
  1035.  
  1036.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1037.         CheckPtrExistence(Window);
  1038.         SetPort((WindowPtr)&(Window->ActualWindow));
  1039.         Poly = OpenPoly();
  1040.         MoveTo(X1,Y1);
  1041.         LineTo(X2,Y2);
  1042.         LineTo(X3,Y3);
  1043.         LineTo(X1,Y1);
  1044.         ClosePoly();
  1045.         PenPat(PatternMapping[Pattern - eWhite]);
  1046.         PenMode(srcCopy);
  1047.         PaintPoly(Poly);
  1048.         KillPoly(Poly);
  1049.     }
  1050.  
  1051.  
  1052. /* Get the ID of a heavier screen font (Macintosh == Chicago) */
  1053. FontType                        GetUglyFont(void)
  1054.     {
  1055.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1056.         return systemFont;
  1057.     }
  1058.  
  1059.  
  1060. /* Get the ID of the default screen font (Macintosh == Geneva) */
  1061. FontType                        GetScreenFont(void)
  1062.     {
  1063.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1064.         return geneva;
  1065.     }
  1066.  
  1067.  
  1068. /* Get the ID of the normal monospaced font, usually courier or monaco */
  1069. FontType                        GetMonospacedFont(void)
  1070.     {
  1071.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1072.         return monaco;
  1073.     }
  1074.  
  1075.  
  1076. /* Get the ID of the named font.  If no such font exists, then it is an error */
  1077. FontType                        GetFontByName(char* Name)
  1078.     {
  1079.         unsigned char            NameTemp[256];
  1080.         long                            Scan;
  1081.         short                            FontID;
  1082.  
  1083.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1084.         Scan = 0;
  1085.         while ((Scan < 255) && (Name[Scan] != 0))
  1086.             {
  1087.                 NameTemp[Scan + 1] = Name[Scan];
  1088.                 Scan += 1;
  1089.             }
  1090.         NameTemp[0] = Scan;
  1091.         GetFNum(NameTemp,&FontID);
  1092. #if DEBUG
  1093.         if (FontID == 0)
  1094.             {
  1095.                 unsigned char            SysFontName[256];
  1096.  
  1097.                 GetFontName(0,SysFontName);
  1098.                 if (!EqualString(NameTemp,SysFontName,False,False))
  1099.                     {
  1100.                         PRERR(AllowResume,"GetFontByName:  font doesn't exist");
  1101.                     }
  1102.             }
  1103. #endif
  1104.         return FontID;
  1105.     }
  1106.  
  1107.  
  1108. /* Get the total number of pixels high a line is using the specified font */
  1109. OrdType                            GetFontHeight(FontType FontID, FontSizeType PointSize)
  1110.     {
  1111.         GrafPort                    Temp;
  1112.         FontInfo                    TheFont;
  1113.  
  1114.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1115.         OpenPort(&Temp);
  1116.         TextFont(FontID);
  1117.         TextFace(0);
  1118.         TextMode(srcCopy);
  1119.         TextSize(PointSize);
  1120.         SpaceExtra(0);
  1121.         GetFontInfo(&TheFont);
  1122.         ClosePort(&Temp);
  1123.         return TheFont.ascent + TheFont.descent + TheFont.leading;
  1124.     }
  1125.  
  1126.  
  1127. /* return a Ptr containing the name of the font, null terminated */
  1128. char*                                GetNameOfFont(FontType FontID)
  1129.     {
  1130.         unsigned char            DaFontName[256];
  1131.         char*                            Temp;
  1132.  
  1133.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1134.         GetFontName(FontID,DaFontName);
  1135.         ERROR(DaFontName[0] == 0,PRERR(AllowResume,"GetNameOfFont:  nonexistent font"));
  1136.         Temp = AllocPtrCanFail(DaFontName[0] + 1,"FontName");
  1137.         if (Temp != NIL)
  1138.             {
  1139.                 CopyData((char*)&(DaFontName[1]),&(Temp[0]),DaFontName[0]);
  1140.                 Temp[DaFontName[0]] = 0;
  1141.             }
  1142.         return Temp;
  1143.     }
  1144.  
  1145.  
  1146. /* get number of fonts */
  1147. long                                GetNumAvailableFonts(void)
  1148.     {
  1149.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1150.         return CountMItems(FunnyFontMenu);
  1151.     }
  1152.  
  1153.  
  1154. /* get the FontType of an indexed font. indices are from 0 to GetNumAvailableFonts - 1 */
  1155. FontType                        GetIndexedFont(long FontIndex)
  1156.     {
  1157.         short                            DaID;
  1158.         unsigned char            DaName[256];
  1159.  
  1160.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1161.         ERROR((FontIndex < 0) || (FontIndex >= GetNumAvailableFonts()),PRERR(ForceAbort,
  1162.             "GetIndexedFont:  index out of range"));
  1163.         /* we cleverly make a menu, pile the fonts in there, and then extract */
  1164.         GetItem(FunnyFontMenu,FontIndex + 1,DaName);
  1165.         GetFNum(DaName,&DaID);
  1166.         return DaID;
  1167.     }
  1168.  
  1169.  
  1170. /* find the total number of pixels long the string of text is */
  1171. OrdType                            LengthOfText(FontType Font, FontSizeType PointSize, char* Text,
  1172.                                             long Length, FontStyleType FontStyle)
  1173.     {
  1174.         GrafPort                    Temp;
  1175.         long                            CurrentLinePixels;
  1176.         Style                            FontThangs;
  1177.  
  1178.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1179.         /* open a temporary port to work from */
  1180.         OpenPort(&Temp);
  1181.         /* set font */
  1182.         TextFont(Font);
  1183.         /* figure out what style to use */
  1184.         FontThangs = 0;
  1185.         if ((FontStyle & eBold) != 0)
  1186.             {
  1187.                 FontThangs |= bold;
  1188.             }
  1189.         if ((FontStyle & eItalic) != 0)
  1190.             {
  1191.                 FontThangs |= italic;
  1192.             }
  1193.         if ((FontStyle & eUnderline) != 0)
  1194.             {
  1195.                 FontThangs |= underline;
  1196.             }
  1197.         TextFace(FontThangs);
  1198.         TextMode(srcCopy);
  1199.         TextSize(PointSize);
  1200.         SpaceExtra(0);
  1201.         /* loop through string & add up lengths */
  1202.         CurrentLinePixels = 0;
  1203.         while (Length > 0)
  1204.             {
  1205.                 if (Length > MAXTEXTSIZING)
  1206.                     {
  1207.                         CurrentLinePixels += TextWidth(Text,0,MAXTEXTSIZING);
  1208.                         Length -= MAXTEXTSIZING;
  1209.                         Text += MAXTEXTSIZING;
  1210.                     }
  1211.                  else
  1212.                     {
  1213.                         CurrentLinePixels += TextWidth(Text,0,Length);
  1214.                         Length = 0;
  1215.                     }
  1216.             }
  1217.         ClosePort(&Temp);
  1218.         return CurrentLinePixels;
  1219.     }
  1220.  
  1221.  
  1222. /* draw a line of text */
  1223. void                                DrawTextLine(WinType* Window, FontType Font, FontSizeType PointSize,
  1224.                                             char* Text, long Length, OrdType X, OrdType Y,
  1225.                                             FontStyleType FontStyle)
  1226.     {
  1227.         FontInfo                    Info;
  1228.         Style                            FontThangs;
  1229.  
  1230.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1231.         ERROR(Text == NIL,PRERR(ForceAbort,"DrawTextLine:  Text is NIL"));
  1232.         CheckPtrExistence(Window);
  1233.         SetPort((WindowPtr)&(Window->ActualWindow));
  1234.         TextFont(Font);
  1235.         FontThangs = 0;
  1236.         if ((FontStyle & eBold) != 0)
  1237.             {
  1238.                 FontThangs |= bold;
  1239.             }
  1240.         if ((FontStyle & eItalic) != 0)
  1241.             {
  1242.                 FontThangs |= italic;
  1243.             }
  1244.         if ((FontStyle & eUnderline) != 0)
  1245.             {
  1246.                 FontThangs |= underline;
  1247.             }
  1248.         TextFace(FontThangs);
  1249.         TextMode(srcCopy);
  1250.         TextSize(PointSize);
  1251.         SpaceExtra(0);
  1252.         GetFontInfo(&Info);
  1253.         MoveTo(X,Y + Info.leading + Info.ascent);
  1254.         while (Length > 0)
  1255.             {
  1256.                 if (Length > MAXTEXTSIZING)
  1257.                     {
  1258.                         DrawText(Text,0,MAXTEXTSIZING);
  1259.                         Length -= MAXTEXTSIZING;
  1260.                         Text += MAXTEXTSIZING;
  1261.                     }
  1262.                  else
  1263.                     {
  1264.                         DrawText(Text,0,Length);
  1265.                         Length = 0;
  1266.                     }
  1267.             }
  1268.         if (Info.leading > 0)
  1269.             {
  1270.                 Rect                EraseMe;
  1271.  
  1272.                 /* since srcCopy doesn't erase the leading, we have to do it. */
  1273.                 EraseMe.left = X;
  1274.                 EraseMe.top = Y;
  1275.                 EraseMe.right = Window->ActualWindow.port.pnLoc.h;
  1276.                 EraseMe.bottom = EraseMe.top + Info.leading;
  1277.                 EraseRect(&EraseMe);
  1278.             }
  1279.     }
  1280.  
  1281.  
  1282. /* draw a line of text, but with white background and black letters */
  1283. void                                InvertedTextLine(WinType* Window, FontType Font,
  1284.                                             FontSizeType PointSize, char* Text, long Length,
  1285.                                             OrdType X, OrdType Y, FontStyleType FontStyle)
  1286.     {
  1287.         FontInfo                    Info;
  1288.         Style                            FontThangs;
  1289.  
  1290.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1291.         CheckPtrExistence(Window);
  1292.         SetPort((WindowPtr)&(Window->ActualWindow));
  1293.         TextFont(Font);
  1294.         FontThangs = 0;
  1295.         if ((FontStyle & eBold) != 0)
  1296.             {
  1297.                 FontThangs |= bold;
  1298.             }
  1299.         if ((FontStyle & eItalic) != 0)
  1300.             {
  1301.                 FontThangs |= italic;
  1302.             }
  1303.         if ((FontStyle & eUnderline) != 0)
  1304.             {
  1305.                 FontThangs |= underline;
  1306.             }
  1307.         TextFace(FontThangs);
  1308.         TextMode(notSrcCopy);
  1309.         TextSize(PointSize);
  1310.         SpaceExtra(0);
  1311.         GetFontInfo(&Info);
  1312.         MoveTo(X,Y + Info.leading + Info.ascent);
  1313.         while (Length > 0)
  1314.             {
  1315.                 if (Length > MAXTEXTSIZING)
  1316.                     {
  1317.                         DrawText(Text,0,MAXTEXTSIZING);
  1318.                         Length -= MAXTEXTSIZING;
  1319.                         Text += MAXTEXTSIZING;
  1320.                     }
  1321.                  else
  1322.                     {
  1323.                         DrawText(Text,0,Length);
  1324.                         Length = 0;
  1325.                     }
  1326.             }
  1327.         if (Info.leading > 0)
  1328.             {
  1329.                 Rect                EraseMe;
  1330.  
  1331.                 /* since srcCopy doesn't erase the leading, we have to do it. */
  1332.                 EraseMe.left = X;
  1333.                 EraseMe.top = Y;
  1334.                 EraseMe.right = Window->ActualWindow.port.pnLoc.h;
  1335.                 EraseMe.bottom = EraseMe.top + Info.leading;
  1336.                 PenPat(qd.black);
  1337.                 PenMode(patCopy);
  1338.                 PaintRect(&EraseMe);
  1339.             }
  1340.     }
  1341.  
  1342.  
  1343. /* move the specified rectangle of of pixels. XDisplacement and YDisplacement */
  1344. /* positive mean to the right and down.  Area opened up is erased with white. */
  1345. /* no area outside of the rectangle is touched. */
  1346. void                                ScrollArea(WinType* Window, OrdType Left, OrdType Top, OrdType Width,
  1347.                                             OrdType Height, OrdType XDisplacement, OrdType YDisplacement)
  1348.     {
  1349.         Rect                            Where;
  1350.         RgnHandle                    UpdateRegion;
  1351.         RgnHandle                    ScreenRegion;
  1352.  
  1353.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1354.         CheckPtrExistence(Window);
  1355.         SetPort((WindowPtr)&(Window->ActualWindow));
  1356.         Where.left = Left;
  1357.         Where.top = Top;
  1358.         Where.right = Left + Width;
  1359.         Where.bottom = Top + Height;
  1360.         UpdateRegion = NewRgn();
  1361.         if (UpdateRegion != NIL)
  1362.             {
  1363.                 ScrollRect(&Where,XDisplacement,YDisplacement,UpdateRegion);
  1364.                 /* we discard the update region because the scroller is expected to redraw */
  1365.                 /* it himself without getting and update event */
  1366.                 DisposeRgn(UpdateRegion);
  1367.             }
  1368.     }
  1369.  
  1370.  
  1371. /* convert a raw packed-byte list of data (upper bit of each byte is leftmost */
  1372. /* on the screen) to an internal bitmap */
  1373. Bitmap*                            MakeBitmap(char* RawData, OrdType Width, OrdType Height,
  1374.                                             long BytesPerRow)
  1375.     {
  1376.         short                            TrueBytesPerRow;
  1377.         short                            RowScan;
  1378.         short                            ColumnScan;
  1379.         long                            MapIndex;
  1380.         Bitmap*                        Data;
  1381.  
  1382.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1383.         ERROR(RawData == NIL,PRERR(ForceAbort,"MakeBitmap:  data is NIL"));
  1384.         /* calculate local bytes per row so that it's a long-word multiple */
  1385.         TrueBytesPerRow = ((Width + (8 * sizeof(long)) - 1) / (8 * sizeof(long))) * 4;
  1386.         Data = (Bitmap*)AllocPtrCanFail(TrueBytesPerRow * Height + sizeof(Bitmap),"Bitmap");
  1387.         if (Data == NIL)
  1388.             {
  1389.                 return NIL;
  1390.             }
  1391.         MapIndex = 0;
  1392.         for (RowScan = 0; RowScan < Height; RowScan += 1)
  1393.             {
  1394.                 /* copy over one row worth of data */
  1395.                 for (ColumnScan = 0; ColumnScan < BytesPerRow; ColumnScan += 1)
  1396.                     {
  1397.                         Data->Data[MapIndex + ColumnScan] = RawData[ColumnScan];
  1398.                     }
  1399.                 /* pad the extra space with zeros */
  1400.                 for (ColumnScan = 0; ColumnScan < TrueBytesPerRow - BytesPerRow;
  1401.                     ColumnScan += 1)
  1402.                     {
  1403.                         Data->Data[MapIndex + ColumnScan + BytesPerRow] = 0;
  1404.                     }
  1405.                 MapIndex += TrueBytesPerRow;
  1406.                 RawData += BytesPerRow;
  1407.             }
  1408.         /* assign internal values */
  1409.         Data->Width = Width;
  1410.         Data->Height = Height;
  1411.         Data->BytesPerRow = TrueBytesPerRow;
  1412.         /* initialize the system's bitmap */
  1413.         Data->SystemBitmap.baseAddr = Data->Data;
  1414.         Data->SystemBitmap.rowBytes = TrueBytesPerRow;
  1415.         Data->SystemBitmap.bounds.left = 0;
  1416.         Data->SystemBitmap.bounds.top = 0;
  1417.         Data->SystemBitmap.bounds.right = Data->Width;
  1418.         Data->SystemBitmap.bounds.bottom = Data->Height;
  1419.         return Data;
  1420.     }
  1421.  
  1422.  
  1423. /* dispose of the bitmap made by MakeBitmap */
  1424. void                                DisposeBitmap(Bitmap* TheBitmap)
  1425.     {
  1426.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1427.         ReleasePtr((char*)TheBitmap);
  1428.     }
  1429.  
  1430.  
  1431. /* copy the bitmap to the area specified. */
  1432. void                                DrawBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1433.     {
  1434.         Rect                            DestRect;
  1435.  
  1436.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1437.         CheckPtrExistence(Window);
  1438.         CheckPtrExistence(TheBitmap);
  1439.         SetPort((WindowPtr)&(Window->ActualWindow));
  1440.         DestRect.left = X;
  1441.         DestRect.top = Y;
  1442.         DestRect.right = X + TheBitmap->Width;
  1443.         DestRect.bottom = Y + TheBitmap->Height;
  1444.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1445.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcCopy,NIL);
  1446.     }
  1447.  
  1448.  
  1449. /* logical-or the bitmap onto the window */
  1450. void                                OrBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1451.     {
  1452.         Rect                            DestRect;
  1453.  
  1454.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1455.         CheckPtrExistence(Window);
  1456.         CheckPtrExistence(TheBitmap);
  1457.         SetPort((WindowPtr)&(Window->ActualWindow));
  1458.         DestRect.left = X;
  1459.         DestRect.top = Y;
  1460.         DestRect.right = X + TheBitmap->Width;
  1461.         DestRect.bottom = Y + TheBitmap->Height;
  1462.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1463.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcOr,NIL);
  1464.     }
  1465.  
  1466.  
  1467. /* Bit-clear the bitmap onto the window:  Where the bitmap is set, the */
  1468. /* window will be erased; otherwise the window will be untouched */
  1469. void                                BicBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1470.     {
  1471.         Rect                            DestRect;
  1472.  
  1473.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1474.         CheckPtrExistence(Window);
  1475.         CheckPtrExistence(TheBitmap);
  1476.         SetPort((WindowPtr)&(Window->ActualWindow));
  1477.         DestRect.left = X;
  1478.         DestRect.top = Y;
  1479.         DestRect.right = X + TheBitmap->Width;
  1480.         DestRect.bottom = Y + TheBitmap->Height;
  1481.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1482.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcBic,NIL);
  1483.     }
  1484.  
  1485.  
  1486. /* duplicate the bitmap */
  1487. Bitmap*                            DuplicateBitmap(Bitmap* Original)
  1488.     {
  1489.         Bitmap*                        Copy;
  1490.         long                            TotalSize;
  1491.  
  1492.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1493.         CheckPtrExistence(Original);
  1494.         /* this is easy since there are no sub-objects */
  1495.         TotalSize = PtrSize((char*)Original);
  1496.         Copy = (Bitmap*)AllocPtrCanFail(TotalSize,"DuplicateBitmap");
  1497.         if (Copy != NIL)
  1498.             {
  1499.                 CopyData((char*)Original,(char*)Copy,TotalSize);
  1500.                 Copy->SystemBitmap.baseAddr = Copy->Data;
  1501.             }
  1502.         return Copy;
  1503.     }
  1504.  
  1505.  
  1506. /* logical-or the first bitmap onto the second.  sizes must be the same */
  1507. void                                BitmapOrIntoBitmap(Bitmap* NotChanged, Bitmap* IsChanged)
  1508.     {
  1509.         long                            Scan;
  1510.         long                            Limit;
  1511.  
  1512.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1513.         CheckPtrExistence(NotChanged);
  1514.         CheckPtrExistence(IsChanged);
  1515.         ERROR((NotChanged->BytesPerRow != IsChanged->BytesPerRow)
  1516.             || (NotChanged->Width != IsChanged->Width)
  1517.             || (NotChanged->Height != IsChanged->Height),PRERR(ForceAbort,
  1518.             "BitmapOrIntoBitmap:  bitmaps are not the same size"));
  1519.         /* we can perform operations on long words since we ensure that our */
  1520.         /* internal bitmap representation is long-word aligned */
  1521.         Limit = (IsChanged->BytesPerRow * IsChanged->Height) / sizeof(unsigned long);
  1522.         for (Scan = 0; Scan < Limit; Scan += 1)
  1523.             {
  1524.                 PRNGCHK(IsChanged,&(((unsigned long*)(IsChanged->Data))[Scan]),
  1525.                     sizeof(unsigned long));
  1526.                 PRNGCHK(NotChanged,&(((unsigned long*)(NotChanged->Data))[Scan]),
  1527.                     sizeof(unsigned long));
  1528.                 ((unsigned long*)(IsChanged->Data))[Scan]
  1529.                     |= ((unsigned long*)(NotChanged->Data))[Scan];
  1530.             }
  1531.     }
  1532.  
  1533.  
  1534. /* logical-and the first bitmap onto the second.  sizes must be the same */
  1535. void                                BitmapAndIntoBitmap(Bitmap* NotChanged, Bitmap* IsChanged)
  1536.     {
  1537.         long                            Scan;
  1538.         long                            Limit;
  1539.  
  1540.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1541.         CheckPtrExistence(NotChanged);
  1542.         CheckPtrExistence(IsChanged);
  1543.         ERROR((NotChanged->BytesPerRow != IsChanged->BytesPerRow)
  1544.             || (NotChanged->Width != IsChanged->Width)
  1545.             || (NotChanged->Height != IsChanged->Height),PRERR(ForceAbort,
  1546.             "BitmapAndIntoBitmap:  bitmaps are not the same size"));
  1547.         /* we can perform operations on long words since we ensure that our */
  1548.         /* internal bitmap representation is long-word aligned */
  1549.         Limit = (IsChanged->BytesPerRow * IsChanged->Height) / sizeof(unsigned long);
  1550.         for (Scan = 0; Scan < Limit; Scan += 1)
  1551.             {
  1552.                 PRNGCHK(IsChanged,&(((unsigned long*)(IsChanged->Data))[Scan]),
  1553.                     sizeof(unsigned long));
  1554.                 PRNGCHK(NotChanged,&(((unsigned long*)(NotChanged->Data))[Scan]),
  1555.                     sizeof(unsigned long));
  1556.                 ((unsigned long*)(IsChanged->Data))[Scan]
  1557.                     &= ((unsigned long*)(NotChanged->Data))[Scan];
  1558.             }
  1559.     }
  1560.